﻿#region zh-CHS 2006 - 2010 DemoSoft 团队 | en 2006-2010 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the MMOSE(Massively Multiplayer Online Server Engine) for .NET.
//
//                              2006-2010 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Diagnostics;
using System.Threading;
using Demo.Mmose.Core.Common;
using Demo.Mmose.Core.Common.SafeCollections;
using Demo.Mmose.Core.Entity.Item;
using Demo.Mmose.Core.Util;
using System.Collections.Generic;
#endregion

namespace Demo.Mmose.Core.Entity.Creature.Suit
{
    /// <summary>
    /// 背包
    /// </summary>
    public class BagManager<ContainerT, ItemT>
        where ContainerT : ItemContainer<ItemT>
        where ItemT : ItemBase
    {
        #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
        /// <summary>
        /// 
        /// </summary>
        public BagManager()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Id"></param>
        public BagManager( long lMinSlot, long lMaxSlot )
        {
            m_MinSlot = lMinSlot;
            m_MaxSlot = lMaxSlot;
        }

        /// <summary>
        /// 
        /// </summary>
        public void InitBagSlot( long lMinSlot, long lMaxSlot )
        {
            if ( lMinSlot < 0 )
                throw new ArgumentOutOfRangeException( "lMinSlot", "BagManager<T>.InitBagSlot(...) - m_MinSlot < 0 error!" );

            if ( lMaxSlot < 0 )
                throw new ArgumentOutOfRangeException( "lMaxSlot", "BagManager<T>.InitBagSlot(...) - lMaxSlot < 0 error!" );

            if ( lMinSlot > lMaxSlot )
                throw new ArgumentException( "lMinSlot & lMaxSlot", "BagManager<T>.InitBagSlot(...) - lMinSlot > lMaxSlot error!" );

            // 清空 初始化
            this.Clear();

            m_MinSlot = lMinSlot;
            m_MaxSlot = lMaxSlot;
        }
        #endregion

        #region zh-CHS 共有属性 | en Public Properties

        #region zh-CHS Serial属性 | en Public Properties

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private Serial m_Serial = new Serial();
        #endregion
        /// <summary>
        /// 道具的唯一序列号GUID
        /// </summary>
        public Serial Serial
        {
            get { return m_Serial; }
            set { m_Serial = value; }
        }

        #endregion

        #region zh-CHS Owner 属性 | en Public Properties

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private Unit m_Owner = null;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public Unit Owner
        {
            get { return m_Owner; }
            set { m_Owner = value; }
        }

        #endregion

        #region zh-CHS MinSlot属性 | en Public Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private long m_MinSlot = 0;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public long MinSlot
        {
            get { return m_MinSlot; }
            protected set
            {
                m_MinSlot = value;

                if ( value < 0 )
                    throw new ArgumentOutOfRangeException( "value", "BagManager<T>.MinSlot - value < 0 error!" );

                if ( value > m_MaxSlot )
                    throw new ArgumentException( "value", "BagManager<T>.MinSlot - value > m_MaxSlot error!" );
            }
        }
        #endregion

        #region zh-CHS MaxSlot属性 | en Public Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private long m_MaxSlot = long.MaxValue;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public long MaxSlot
        {
            get { return m_MaxSlot; }
            protected set
            {
                if ( value < 0 )
                    throw new ArgumentOutOfRangeException( "value", "BagManager<T>.MaxSlot - value < 0 error!" );

                if ( value < m_MinSlot )
                    throw new ArgumentException( "value", "BagManager<T>.MaxSlot - value < m_MinSlot error!" );

                m_MaxSlot = value;
            }
        }
        #endregion

        #region zh-CHS IsBagFull属性 | en Public Properties
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool IsBagFull
        {
            get
            {
                if ( m_ToteContainers.Count < ( ( this.MaxSlot - this.MinSlot ) + 1 ) )
                    return false;
                else
                    return true;
            }
        }
        #endregion

        #region zh-CHS FreeBagCount属性 | en Public Properties
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public int FreeBagCount
        {
            get
            {
                return ( ( (int)this.MaxSlot - (int)this.MinSlot ) + 1 ) - m_ToteContainers.Count;
            }
        }
        #endregion

        #region zh-CHS FreeCount属性 | en Public Properties
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public int FreeCount
        {
            get
            {
                int freeCount = 0;

                foreach ( var item in m_ToteContainers )
                {
                    if ( item.Value != null )
                        freeCount += item.Value.FreeCount;
                }

                return freeCount;
            }
        }
        #endregion

        #region zh-CHS ItemContainer 属性 | en Public Properties

        #region zh-CHS 私有常量 | en Private Constants
        /// <summary>
        /// 
        /// </summary>
        private readonly static ContainerT[] s_ZeroValueArray = new ContainerT[0];
        #endregion

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 人物的道具列表
        /// </summary>
        private Dictionary<long, ContainerT> m_ToteContainers = new Dictionary<long, ContainerT>();
        /// <summary>
        /// 
        /// </summary>
        private ReaderWriterLockSlim m_LockToteSubItems = new ReaderWriterLockSlim();
        /// <summary>
        /// 
        /// </summary>
        private volatile ContainerT[] m_ValueArray = s_ZeroValueArray;
        /// <summary>
        /// 
        /// </summary>
        private volatile bool m_bIsValueChange = true;
        #endregion

        #region zh-CHS 私有方法 | en Private Methods
        /// <summary>
        /// 
        /// </summary>
        private void InternalToCached()
        {
            if ( m_bIsValueChange == false )
                return;

            m_LockToteSubItems.EnterReadLock();
            try
            {
                if ( m_bIsValueChange == true )
                {
                    m_ValueArray = new ContainerT[m_ToteContainers.Count];

                    int iIndex = 0;
                    foreach ( KeyValuePair<long, ContainerT> keyValuePair in m_ToteContainers )
                    {
                        m_ValueArray[iIndex] = keyValuePair.Value;
                        ++iIndex;
                    }

                    // 最后设置
                    m_bIsValueChange = false;
                }
            }
            finally
            {
                m_LockToteSubItems.ExitReadLock();
            }
        }
        #endregion

        /// <summary>
        /// 人物的道具列表(包裹与身上)
        /// </summary>
        /// <returns></returns>
        [MultiThreadedWarning( "zh-CHS", "(道具)当前的数组是列表临时产生的,不能保存数组用于以后操作:警告!" )]
        public ContainerT[] ToArray()
        {
            InternalToCached();

            return m_ValueArray;
        }

        #region zh-CHS 共有方法 | en Public Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public bool AddContainer( long lBagSlot, ContainerT itemContainer )
        {
            if ( itemContainer == null )
                throw new Exception( "BaseBagHandler.AddContainer(...) - itemContainer == null error!" );

            if ( lBagSlot == ItemContainer.SlotNotSet )
                return false;

            if ( lBagSlot > this.MaxSlot || lBagSlot < this.MinSlot )
                return false;

            EventHandler<AddingItemContainerCallEventArgs<ContainerT, ItemT>> tempBeforeEventArgs = m_EventAddingItemContainer;
            if ( tempBeforeEventArgs != null )
            {
                AddingItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new AddingItemContainerCallEventArgs<ContainerT, ItemT>( itemContainer, this );
                tempBeforeEventArgs( this, eventArgs );

                if ( eventArgs.IsCancel == true )
                    return false;
            }

            bool tryAdd = false;

            m_LockToteSubItems.EnterWriteLock();
            try
            {
                if ( m_ToteContainers.ContainsKey( lBagSlot ) == false )
                {
                    m_ToteContainers.Add( lBagSlot, itemContainer );
                    itemContainer.BagSlotId = lBagSlot;

                    m_bIsValueChange = tryAdd = true;
                }
            }
            finally
            {
                m_LockToteSubItems.ExitWriteLock();
            }

            if ( tryAdd == false )
                return false;

            EventHandler<AddedItemContainerCallEventArgs<ContainerT, ItemT>> tempAfterEventArgs = m_EventAddedItemContainer;
            if ( tempAfterEventArgs != null )
            {
                AddedItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new AddedItemContainerCallEventArgs<ContainerT, ItemT>( itemContainer, this );
                tempAfterEventArgs( this, eventArgs );
            }

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public bool RemoveContainer( long lBagSlot )
        {
            if ( lBagSlot > this.MaxSlot || lBagSlot < this.MinSlot )
                return false;

            ContainerT itemContainer = FindContainerOnSlot( lBagSlot );
            if ( itemContainer == null )
                return false;

            EventHandler<RemovingItemContainerCallEventArgs<ContainerT, ItemT>> tempBeforeEventArgs = m_EventRemovingItemContainer;
            if ( tempBeforeEventArgs != null )
            {
                RemovingItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new RemovingItemContainerCallEventArgs<ContainerT, ItemT>( itemContainer, this );
                tempBeforeEventArgs( this, eventArgs );
                
                if ( eventArgs.IsCancel == true )
                    return false;
            }


            bool isRemove = false;

            m_LockToteSubItems.EnterWriteLock();
            try
            {
                if ( m_ToteContainers.Remove( lBagSlot ) == true )
                    m_bIsValueChange = isRemove = true;

                itemContainer.BagSlotId = ItemBase.SlotNotSet;
            }
            finally
            {
                m_LockToteSubItems.ExitWriteLock();
            }

            if ( isRemove == false )
                return false;

            EventHandler<RemovedItemContainerCallEventArgs<ContainerT, ItemT>> tempAfterEventArgs = m_EventRemovedItemContainer;
            if ( tempAfterEventArgs != null )
            {
                RemovedItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new RemovedItemContainerCallEventArgs<ContainerT, ItemT>( itemContainer, this );
                tempAfterEventArgs( this, eventArgs );
            }

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public bool RemoveSubItem( long lBagSlot, long lItemSlot )
        {
            if ( lBagSlot > this.MaxSlot || lBagSlot < this.MinSlot )
                return false;

            ContainerT itemContainer = FindContainerOnSlot( lBagSlot );
            if ( itemContainer == null )
                return false;

            return itemContainer.RemoveSubItem( lItemSlot );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="srcBagSlot"></param>
        /// <param name="dstBagSlot"></param>
        /// <returns></returns>
        public bool SwapSubContainer( long srcBagSlot, long dstBagSlot )
        {
            if ( srcBagSlot > this.MaxSlot || srcBagSlot < this.MinSlot )
                return false;

            if ( dstBagSlot > this.MaxSlot || dstBagSlot < this.MinSlot )
                return false;

            ContainerT srcContainer = FindContainerOnSlot( srcBagSlot );
            if ( srcContainer == null )
                return false;

            ContainerT dstContainer = FindContainerOnSlot( dstBagSlot );

            EventHandler<SwapingItemContainerCallEventArgs<ContainerT, ItemT>> tempBeforeEventArgs = m_EventSwapingItemContainer;
            if ( tempBeforeEventArgs != null )
            {
                SwapingItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new SwapingItemContainerCallEventArgs<ContainerT, ItemT>( srcBagSlot, srcContainer, dstBagSlot, dstContainer, this );
                tempBeforeEventArgs( this, eventArgs );

                if ( eventArgs.IsCancel == true )
                    return false;
            }

            bool isSwap = false;

            m_LockToteSubItems.EnterWriteLock();
            try
            {
                do
                {
                    bool srcIsNone = false;
                    ContainerT srcValue = default( ContainerT );
                    if ( m_ToteContainers.TryGetValue( srcBagSlot, out srcValue ) == false )
                        break;

                    bool dstIsNone = false;
                    ContainerT dstValue = default( ContainerT );
                    if ( m_ToteContainers.TryGetValue( dstBagSlot, out dstValue ) == false )
                        dstIsNone = true;

                    if ( srcIsNone == false )       // 来源数据存在，添加数据
                    {
                        m_ToteContainers[dstBagSlot] = srcValue;
                        srcValue.BagSlotId = dstBagSlot;
                    }
                    else                            // 来源数据不存在，删除目标数据
                    {
                        if ( dstIsNone == false )   // 如果目标数据存在，删除目标数据（因为来源数据不存在）
                            m_ToteContainers.Remove( dstBagSlot );
                    }

                    if ( dstIsNone == false )       // 目标数据存在，添加数据
                    {
                        m_ToteContainers[srcBagSlot] = dstValue;
                        dstValue.BagSlotId = srcBagSlot;
                    }
                    else                            // 目标数据不存在，删除来源数据
                    {
                        if ( srcIsNone == false )   // 如果来源数据存在，删除来源数据（因为目标数据不存在）
                            m_ToteContainers.Remove( srcBagSlot );
                    }

                    m_bIsValueChange = isSwap = true;
                } while ( false );
            }
            finally
            {
                m_LockToteSubItems.ExitWriteLock();
            }

            if ( isSwap == false )
                return false;

            EventHandler<SwapedItemContainerCallEventArgs<ContainerT, ItemT>> tempAfterEventArgs = m_EventSwapedItemContainer;
            if ( tempAfterEventArgs != null )
            {
                SwapedItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new SwapedItemContainerCallEventArgs<ContainerT, ItemT>( srcBagSlot, srcContainer, dstBagSlot, dstContainer, this );
                tempAfterEventArgs( this, eventArgs );
            }

            return true;
        }

        /// <summary>
        /// 找道具
        /// </summary>
        /// <param name="layer"></param>
        /// <returns></returns>
        public ContainerT FindContainerOnSlot( long lContainerSlot )
        {
            ContainerT containerT = default( ContainerT );

            m_LockToteSubItems.EnterReadLock();
            try
            {
                m_ToteContainers.TryGetValue( lContainerSlot, out containerT );
            }
            finally
            {
                m_LockToteSubItems.ExitReadLock();
            }

            return containerT;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            ContainerT[] valueArray = null;

            m_LockToteSubItems.EnterWriteLock();
            try
            {
                if ( m_bIsValueChange == true )
                {
                    m_ValueArray = new ContainerT[m_ToteContainers.Count];

                    int iIndex = 0;
                    foreach ( KeyValuePair<long, ContainerT> keyValuePair in m_ToteContainers )
                    {
                        m_ValueArray[iIndex] = keyValuePair.Value;
                        keyValuePair.Value.BagSlotId = ItemBase.SlotNotSet;

                        ++iIndex;
                    }
                }

                valueArray = m_ValueArray;

                // 清空
                m_ToteContainers.Clear();
                m_ValueArray = s_ZeroValueArray;

                // 最后设置
                m_bIsValueChange = false;
            }
            finally
            {
                m_LockToteSubItems.ExitWriteLock();
            }

            if ( valueArray == null )
                return;

            foreach ( var item in valueArray )
            {
                EventHandler<RemovedItemContainerCallEventArgs<ContainerT, ItemT>> tempAfterEventArgs = m_EventRemovedItemContainer;
                if ( tempAfterEventArgs != null )
                {
                    RemovedItemContainerCallEventArgs<ContainerT, ItemT> eventArgs = new RemovedItemContainerCallEventArgs<ContainerT, ItemT>( item, this );
                    tempAfterEventArgs( this, eventArgs );
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public bool AddToFreeContainerSlot( ContainerT itemContainerT )
        {
            long lItemContainerSlotResult = ItemContainer.SlotNotSet;

            if ( this.IsBagFull == true )
                return false;

            bool tryAdd = false;

            m_LockToteSubItems.EnterWriteLock();
            try
            {

                for ( long iIndexSlot = this.MinSlot; iIndexSlot <= this.MaxSlot; iIndexSlot++ )
                {
                    if ( m_ToteContainers.ContainsKey( iIndexSlot ) == true )
                        continue;
                    else
                    {
                        m_ToteContainers.Add( iIndexSlot, itemContainerT );
                        itemContainerT.BagSlotId = iIndexSlot;

                        m_bIsValueChange = tryAdd = true;

                        break;
                    }
                }
            }
            finally
            {
                m_LockToteSubItems.ExitWriteLock();
            }

            return tryAdd;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="layer"></param>
        /// <returns></returns>
        public bool TryFindFreeContainerSlot( ref long lItemContainerSlotResult )
        {
            if ( this.IsBagFull == true )
                return false;

            bool isFind = false;

            m_LockToteSubItems.EnterReadLock();
            try
            {
                for ( long iIndexSlot = this.MinSlot; iIndexSlot <= this.MaxSlot; iIndexSlot++ )
                {
                    if ( m_ToteContainers.ContainsKey( iIndexSlot ) == true )
                        continue;
                    else
                    {
                        isFind = true;
                        lItemContainerSlotResult = iIndexSlot;

                        break;
                    }
                }
            }
            finally
            {
                m_LockToteSubItems.ExitReadLock();
            }

            return isFind;
        }
        #endregion

        #endregion

        #region zh-CHS Count属性 | en Public Properties

        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get { return m_ToteContainers.Count; }
        }

        #endregion

        #region zh-CHS ItemCount属性 | en Public Properties

        /// <summary>
        /// 
        /// </summary>
        public int ItemCount
        {
            get
            {
                int iCount = 0;
                foreach ( var container in m_ToteContainers )
                {
                    if ( container.Value == null )
                        continue;

                    iCount += container.Value.Count;
                }

                return iCount;
            }
        }

        #endregion

        #endregion

        #region zh-CHS 共有方法 | en Public Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="wowItem"></param>
        /// <returns></returns>
        public ContainerT FindSpecialBag( ItemT item )
        {
            if ( item == null )
                return null;

            ContainerT[] itemContainerArray = this.ToArray();
            if ( itemContainerArray == null )
                return null;

            for ( int iIndex = 0; iIndex < itemContainerArray.Length; iIndex++ )
            {
                ContainerT itemContainer = itemContainerArray[iIndex];
                ItemT[] itemArray = itemContainer.ToArray();
                if ( itemContainerArray == null )
                    continue;

                for ( int iIndex2 = 0; iIndex2 < itemArray.Length; iIndex2++ )
                {
                    if ( itemArray[iIndex2] == item )
                        return itemContainer;
                }
            }

            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="layer"></param>
        /// <returns></returns>
        public ItemT FindSubItemOnContainerSlot( long lContainerSlot, long lItemSlot )
        {
            ContainerT itemContainer = FindContainerOnSlot( lContainerSlot );
            if ( itemContainer == null )
                return null;

            return itemContainer.FindSubItemOnSlot( lItemSlot );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseItem"></param>
        /// <returns></returns>
        public bool AddSubItemToSpecialContainer( long lContainerSlot, long lItemSlot, ItemT item )
        {
            ContainerT itemContainer = FindContainerOnSlot( lContainerSlot );
            if ( itemContainer == null )
                return false;

            return itemContainer.AddSubItem( lItemSlot, item );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseItem"></param>
        /// <returns></returns>
        public bool AddSubItemToFreeContainer( ItemT item )
        {
            ContainerT[] itemContainerArray = this.ToArray();
            if ( itemContainerArray == null )
                return false;

            for ( int iIndex = 0; iIndex < itemContainerArray.Length; iIndex++ )
            {
                ContainerT itemContainer = itemContainerArray[iIndex];
                if ( itemContainer == null )
                    return false;

                if ( itemContainer.IsContainerFull == true )
                    continue;

                if ( itemContainer.AddToFreeSlot( item ) == true )
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        public struct AddSubItemToFreeContainerResult
        {
            internal List<ItemT> m_Added;
            public IEnumerable<ItemT> Added
            {
                get { return m_Added; }
            }

            internal List<ItemT> m_NotAdded;
            public IEnumerable<ItemT> NotAdded
            {
                get { return m_NotAdded; }
            }

            internal int m_AddedCount;
            public int AddedCount
            {
                get { return m_AddedCount; }
            }

            internal int m_NotAddedCount;
            public int NotAddedCount
            {
                get { return m_NotAddedCount; }
            }

            internal bool m_IsSucceeded;
            public bool IsSucceeded
            {
                get { return m_IsSucceeded; }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseItem"></param>
        /// <returns></returns>
        public AddSubItemToFreeContainerResult AddSubItemToFreeContainer( ICollection<ItemT> items, bool allSucceeded )
        {
            AddSubItemToFreeContainerResult result = new AddSubItemToFreeContainerResult { m_Added = new List<ItemT>( items.Count ), m_NotAdded = new List<ItemT>( items.Count ), m_AddedCount = 0, m_NotAddedCount = 0, m_IsSucceeded = false };

            if ( allSucceeded == false ) // 局部添加
            {
                foreach ( var item in items )
                {
                    if ( this.AddSubItemToFreeContainer( item ) == false )
                    {
                        result.m_NotAddedCount++;
                        result.m_NotAdded.Add( item );

                        continue;
                    }
                    else
                    {
                        result.m_AddedCount++;
                        result.m_Added.Add( item );
                    }

                    m_bIsValueChange = true;
                }

                result.m_IsSucceeded = true;
            }
            else // 全部添加
            {
                if ( this.FreeCount < items.Count )
                    return result;

                m_LockToteSubItems.EnterWriteLock();
                try
                {
                    do
                    {
                        if ( this.FreeCount < items.Count )
                            break;

                        bool isCancel = false;
                        int freeCount = this.FreeCount;
                        int itemCount = 0;
                        List<ContainerT> listContainer = new List<ContainerT>();


                        foreach ( var item in items )
                        {

                            foreach ( var itemContainer in this.ToArray() )
                            {
                                if ( itemContainer.FreeCount <= 0 )
                                    continue;

                                for ( ; itemCount <= 0; itemCount++ )
                                {

                                }


                                EventHandler<AddingSubItemCallEventArgs<ItemT>> tempBeforeEventArgs = itemContainer.m_EventAddingSubItem;
                                if ( tempBeforeEventArgs != null )
                                {
                                    AddingSubItemCallEventArgs<ItemT> eventArgs = new AddingSubItemCallEventArgs<ItemT>( item, itemContainer );
                                    tempBeforeEventArgs( this, eventArgs );

                                    if ( eventArgs.IsCancel == true )
                                    {
                                        freeCount--;
                                        isCancel = true;
                                        break;

                                    }
                                    else
                                    {
                                        itemCount++;
                                    }
                                }

                                if ( isCancel == true )
                                    break;
                            }
                             
                            //if ( isCancel == true )
                            //{
                            //    freeCount -= itemContainer.Count;
                            //    if ( freeCount < items.Count )
                            //        isCancel = false;
                            //    else
                            //        break;
                            //}

                            //listContainer.Add( itemContainer );
                        }

                        if ( isCancel == true )
                            break;

                        // 正式开始添加道具
                        freeCount = 0; // 重新初始化

                        // 开始加锁
                        foreach ( var itemContainer in listContainer )
                        {
                            itemContainer.m_LockToteSubItems.EnterWriteLock();

                            freeCount += itemContainer.FreeCount; // 锁住以后才计算空闲的容器
                        }

                        do
                        {
                            if ( freeCount <= items.Count ) // 再次检查
                                break;

                            ItemT[] itemArray = new ItemT[items.Count];
                            items.CopyTo( itemArray, 0 );

                            int iIndexItem = 0; //当前容器内道具的索引

                            foreach ( var itemContainer in listContainer ) // 开始枚举容器
                            {
                                long iIndexSlot = itemContainer.MinSlot; // 获取容器最小的插槽

                                for ( ; iIndexItem <= items.Count; iIndexItem++ ) // 开始枚举道具，准备添加道具
                                {
                                    ItemT item = itemArray[iIndexItem];
                                    if ( item == null )
                                        throw new Exception( "BagManager.AddSubItemToFreeContainer(...) - item == null error!" );

                                    for ( ; iIndexSlot <= this.MaxSlot; iIndexSlot++ ) // 开始枚举容器所有空闲的插槽
                                    {
                                        if ( itemContainer.m_ToteSubItems.ContainsKey( iIndexSlot ) == true )
                                            continue;

                                        itemContainer.m_ToteSubItems.Add( iIndexSlot, item );
                                        item.SlotId = iIndexSlot;
                                        
                                        result.m_AddedCount++;
                                        result.m_Added.Add( item );

                                        break; // 添加完成
                                    }

                                    // 完成添加道具的事件
                                    EventHandler<AddedSubItemCallEventArgs<ItemT>> tempAfterEventArgs = itemContainer.m_EventAddedSubItem;
                                    if ( tempAfterEventArgs != null )
                                    {
                                        AddedSubItemCallEventArgs<ItemT> eventArgs = new AddedSubItemCallEventArgs<ItemT>( item, itemContainer );
                                        tempAfterEventArgs( this, eventArgs );
                                    }

                                    if ( itemContainer.IsContainerFull == true )
                                        break;
                                }

                                if ( iIndexItem >= items.Count ) // 如果容器内的道具已经全部添加完成，则跳出循环
                                    break;
                            }

                            m_bIsValueChange = true;

                        } while ( false );

                        // 开始解锁
                        foreach ( var itemContainer in listContainer )
                            itemContainer.m_LockToteSubItems.ExitWriteLock();

                    } while ( false );
                }
                finally
                {
                    m_LockToteSubItems.ExitWriteLock();
                }
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="iContainerSlotForm"></param>
        /// <param name="iItemSlotForm"></param>
        /// <param name="iContainerSlotTo"></param>
        /// <returns></returns>
        public bool MoveSubItemToSpecialContainer( long lContainerSlotForm, long lItemSlotForm, long lContainerSlotTo )
        {
            // 获取容器
            ContainerT itemContainerForm = FindContainerOnSlot( lContainerSlotForm );
            if ( itemContainerForm == null )
                return false;

            // 获取容器里面的道具
            ItemT itemForm = itemContainerForm.FindSubItemOnSlot( lItemSlotForm );
            if ( itemForm == null )
                return false;

            // 获取需要放道具的指定容器
            ContainerT itemContainerTo = FindContainerOnSlot( lContainerSlotTo );
            if ( itemContainerTo == null )
                return false;

            long lRetrunItemSlot = ItemBase.SlotNotSet;

            // 尝试寻找指定容器的空闲位置
            if ( itemContainerTo.TryFindFreeSlot( ref lRetrunItemSlot ) == false )
                return false;

            // 开始移除原来容器里面的道具
            if ( itemContainerForm.RemoveSubItem( lItemSlotForm ) == false )
                return false;

            // 开始添加道具到指定的容器
            if ( itemContainerTo.AddSubItem( lRetrunItemSlot, itemForm ) == false ) // 尝试把道具添加到指定的位置
            {
                if ( itemContainerForm.AddToFreeSlot( itemForm ) == false ) // 尝试把道具添加到空闲的位置
                {
                    if ( itemContainerForm.AddSubItem( lItemSlotForm, itemForm ) == false ) // 如果以上都失败了，就把道具放到原来的位置
                    {
                        if ( itemContainerForm.AddToFreeSlot( itemForm ) == false ) // 还是失败了，则把道具添加到原来容器的空闲位置
                        {
                            if ( this.AddSubItemToFreeContainer( itemForm ) == false ) // 还是失败了，则把道具添加到背包里面的容器的空闲位置
                            {
                                // 致命错误，道具丢失了。
                                throw new Exception( "BagManager.MoveSubItemToSpecialContainer(...) - itemContainerForm.AddToFreeSlot(...) error! (No Complete, Lost itemForm)" );
                            }
                        }
                    }
                }

                return false;
            }
            else
                return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="iContainerSlotForm"></param>
        /// <param name="iItemSlotForm"></param>
        /// <param name="iContainerSlotTo"></param>
        /// <param name="iItemSlotTo"></param>
        /// <returns></returns>
        public bool SwapSubItem( long lContainerSlotForm, long lItemSlotForm, long lContainerSlotTo, long lItemSlotTo )
        {
            // 获取容器
            ContainerT itemContainerForm = FindContainerOnSlot( lContainerSlotForm );
            if ( itemContainerForm == null )
                return false;

            // 获取容器里面的道具
            ItemT itemForm = itemContainerForm.FindSubItemOnSlot( lItemSlotForm );
            if ( itemForm == null )
                return false;

            // 获取需要交换的指定容器
            ContainerT itemContainerTo = FindContainerOnSlot( lContainerSlotTo );
            if ( itemContainerTo == null )
                return false;

            // 获取需要交换的指定容器里面的道具
            ItemT itemTo = itemContainerTo.FindSubItemOnSlot( lItemSlotTo );
            if ( itemTo == null )
                return false;

            // 开始移除原来容器里面的道具
            if ( itemContainerForm.RemoveSubItem( lItemSlotForm ) == false )
                return false;

            // 开始移除交换的指定容器里面的道具
            if ( itemContainerTo.RemoveSubItem( lItemSlotTo ) == false ) // 尝试把道具移除
            {
                if ( itemContainerForm.AddSubItem( lItemSlotForm, itemForm ) == false ) // 如果失败，还原删除的道具
                {
                    if ( itemContainerForm.AddToFreeSlot( itemForm ) == false ) // 如果还原失败，添加原来的道具到原来容器里面的空闲位置
                    {
                        if ( this.AddSubItemToFreeContainer( itemForm ) == false ) // 如果还是失败了，添加到背包里容器的空闲位置
                        {
                            // 致命错误，道具丢失了。
                            throw new Exception( "BagManager.SwapSubItem(...) - itemContainerTo.RemoveSubItem(.1.) error! (No Complete, Lost itemForm)" );
                        }
                    }
                }
            }

            // 开始交换道具
            if ( itemContainerForm.AddSubItem( lItemSlotForm, itemTo ) == false )
            {
                if ( itemContainerForm.AddToFreeSlot( itemTo ) == false ) // 失败了，添加到指定容器的空闲位置
                {
                    if ( this.AddSubItemToFreeContainer( itemTo ) == false ) // 如果还是失败了，添加到背包里容器的空闲位置
                        // 致命错误，道具丢失了。
                        throw new Exception( "BagManager.SwapSubItem(...) - itemContainerForm.AddSubItem(.1.) error! (No Complete, Lost itemForm)" );
                }

                if ( itemContainerTo.AddSubItem( lItemSlotTo, itemForm ) == false )
                {
                    if ( itemContainerTo.AddToFreeSlot( itemForm ) == false ) // 失败了，添加到原来容器的空闲位置
                    {
                        if ( this.AddSubItemToFreeContainer( itemForm ) == false ) // 如果还是失败了，添加到背包里容器的空闲位置
                        {
                            // 致命错误，道具丢失了。
                            throw new Exception( "BagManager.SwapSubItem(...) - itemContainerForm.AddSubItem(.2.) error! (No Complete, Lost itemTo)" );
                        }
                    }
                }
            }

            // 开始交换道具
            if ( itemContainerTo.AddSubItem( lItemSlotTo, itemForm ) == false )
            {
                if ( itemContainerTo.AddToFreeSlot( itemForm ) == false ) // 失败了，添加到指定容器的空闲位置
                {
                    if ( this.AddSubItemToFreeContainer( itemForm ) == false ) // 失败了，添加到背包里面容器的空闲位置
                    {
                        // 致命错误，道具丢失了。
                        throw new Exception( "BagManager.SwapSubItem(...) - itemContainerTo.AddSubItem(...) error!" );
                    }
                }
            }

            return true;
        }

        #endregion

        #region zh-CHS 共有事件 | en Public Event

        #region zh-CHS AddItemContainerCall事件 | en Public Event
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<AddingItemContainerCallEventArgs<ContainerT, ItemT>> m_EventAddingItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventAddingItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<AddingItemContainerCallEventArgs<ContainerT, ItemT>> AddingItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventAddingItemContainer );
                try
                {
                    m_EventAddingItemContainer += value;
                }
                finally
                {
                    m_LockEventAddingItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventAddingItemContainer );
                try
                {
                    m_EventAddingItemContainer -= value;
                }
                finally
                {
                    m_LockEventAddingItemContainer.Exit();
                }
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<AddedItemContainerCallEventArgs<ContainerT, ItemT>> m_EventAddedItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventAddedItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<AddedItemContainerCallEventArgs<ContainerT, ItemT>> AddedItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventAddedItemContainer );
                try
                {
                    m_EventAddedItemContainer += value;
                }
                finally
                {
                    m_LockEventAddedItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventAddedItemContainer );
                try
                {
                    m_EventAddedItemContainer -= value;
                }
                finally
                {
                    m_LockEventAddedItemContainer.Exit();
                }
            }
        }
        #endregion

        #region zh-CHS RemoveItemContainerCall事件 | en Public Event
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<RemovingItemContainerCallEventArgs<ContainerT, ItemT>> m_EventRemovingItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventRemovingItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<RemovingItemContainerCallEventArgs<ContainerT, ItemT>> RemovingItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventRemovingItemContainer );
                try
                {
                    m_EventRemovingItemContainer += value;
                }
                finally
                {
                    m_LockEventRemovingItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventRemovingItemContainer );
                try
                {
                    m_EventRemovingItemContainer -= value;
                }
                finally
                {
                    m_LockEventRemovingItemContainer.Exit();
                }
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<RemovedItemContainerCallEventArgs<ContainerT, ItemT>> m_EventRemovedItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventRemovedItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<RemovedItemContainerCallEventArgs<ContainerT, ItemT>> RemovedItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventRemovedItemContainer );
                try
                {
                    m_EventRemovedItemContainer += value;
                }
                finally
                {
                    m_LockEventRemovedItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventRemovedItemContainer );
                try
                {
                    m_EventRemovedItemContainer -= value;
                }
                finally
                {
                    m_LockEventRemovedItemContainer.Exit();
                }
            }
        }
        #endregion

        #region zh-CHS SwapItemContainerCall事件 | en Public Event
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<SwapingItemContainerCallEventArgs<ContainerT, ItemT>> m_EventSwapingItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventSwapingItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<SwapingItemContainerCallEventArgs<ContainerT, ItemT>> SwapingItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventSwapingItemContainer );
                try
                {
                    m_EventSwapingItemContainer += value;
                }
                finally
                {
                    m_LockEventSwapingItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventSwapingItemContainer );
                try
                {
                    m_EventSwapingItemContainer -= value;
                }
                finally
                {
                    m_LockEventSwapingItemContainer.Exit();
                }
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<SwapedItemContainerCallEventArgs<ContainerT, ItemT>> m_EventSwapedItemContainer;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventSwapedItemContainer = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<SwapedItemContainerCallEventArgs<ContainerT, ItemT>> SwapedItemContainer
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventSwapedItemContainer );
                try
                {
                    m_EventSwapedItemContainer += value;
                }
                finally
                {
                    m_LockEventSwapedItemContainer.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventSwapedItemContainer );
                try
                {
                    m_EventSwapedItemContainer -= value;
                }
                finally
                {
                    m_LockEventSwapedItemContainer.Exit();
                }
            }
        }
        #endregion

        #region zh-CHS ThreadLostItemCall事件 | en Public Event
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private EventHandler<LostItemCallEventArgs<ContainerT, ItemT>> m_EventLostItemCall;
        /// <summary>
        /// 
        /// </summary>
        private SpinLock m_LockEventLostItemCall = new SpinLock();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<LostItemCallEventArgs<ContainerT, ItemT>> ThreadLostItemCall
        {
            add
            {
                SpinLockEx.ReliableEnter( ref m_LockEventLostItemCall );
                try
                {
                    m_EventLostItemCall += value;
                }
                finally
                {
                    m_LockEventLostItemCall.Exit();
                }
            }
            remove
            {
                SpinLockEx.ReliableEnter( ref m_LockEventLostItemCall );
                try
                {
                    m_EventLostItemCall -= value;
                }
                finally
                {
                    m_LockEventLostItemCall.Exit();
                }
            }
        }
        #endregion

        #endregion
    }
}
#endregion